package org.ala.tiktools.rpc.client_server.service;

import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.function.Consumer;

import org.ala.tiktools.logs.LoggerFactory;
import org.ala.tiktools.rpc.config.RpcConfigInfo;
import org.ala.tiktools.rpc.exception.RpcException;
import org.ala.tiktools.tools.ReflectionTools;
import org.ala.tiktools.tools.thread_pool.ThreadPoolTools;
import org.slf4j.Logger;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.PutMapping;

/**
 * AlaRpcService 执行器
 * <p>  全局唯一
 *
 * @author ala
 * @date 2025-04-07 14:07
 */
public class RpcServiceExecutor implements ApplicationContextAware {


    static Logger log = LoggerFactory.getLogger("rpc", "rpc-service");


    /**
     *
     */
    protected ApplicationContext context;
    /**
     *  服务端线程池（公共线程池）
     */
    protected ThreadPoolExecutor commonThreadPool;
    /**
     *  MethodExecutor映射
     */
    protected Map<String, RpcMethodExecutor> executor = new HashMap<>();


    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        context = applicationContext;
        commonThreadPool = ThreadPoolTools.build(
                RpcConfigInfo.INSTANCE.getServiceCoreSize(), RpcConfigInfo.INSTANCE.getServiceMaxSize(),
                RpcConfigInfo.INSTANCE.getServiceQueueSize(),
                "RpcServiceCommonThread");
        init();
    }


    /**
     *  执行方法
     */
    public void invoke(String url, Object[] args, Map<String, Object> metadata, Consumer<RpcExecuteResult> consumer) {
        RpcMethodExecutor me = executor.get(url);
        if (me == null) {
            log.warn("[RpcServiceExecutor invoke] 找不到url对应的方法 url:{}", url);
            consumer.accept(RpcExecuteResult.build().success(false).e(new RpcException("找不到url对应的方法")));
            return;
        }
        me.invoke(args, metadata, consumer);
    }


    /**
     *  初始化方法
     */
    protected void init() {
        //  根据注解拿bean
        Map<String, Object> map = context.getBeansWithAnnotation(AlaRpcService.class);
        //  解析bean
        map.values().forEach(this::parseMethod);
    }
    /**
     *  解析bean中的所有方法
     */
    @SuppressWarnings("unchecked")
	protected void parseMethod(Object bean) {
        ThreadPoolExecutor threadPool = commonThreadPool;
        AlaRpcService anno = bean.getClass().getAnnotation(AlaRpcService.class);
        if (anno.threadPoolCoreSize() > 0 && anno.threadPoolMaxSize() > 0 && anno.threadPoolQueueSize() > 0) {
            threadPool = ThreadPoolTools.build(
                    anno.threadPoolCoreSize(), anno.threadPoolMaxSize(),
                    anno.threadPoolQueueSize(),
                    String.format("RpcServiceThread_%s", bean.getClass().getSimpleName()));
        }
        String rootPath = anno.path();
        if (rootPath.length() > 0 && rootPath.charAt(rootPath.length()-1) == '/') {
            rootPath = rootPath.substring(0, rootPath.length()-1);
        }

        //  解析全部的*Mapper注解
        List<ReflectionTools.AnnotationMethod> list = ReflectionTools.methodByAnnotations(bean.getClass(), PostMapping.class, GetMapping.class, PutMapping.class);
        for (ReflectionTools.AnnotationMethod am : list) {
            Method m = am.getMethod();
            String url = getUrl(bean, am, m);
            if (url.charAt(0) == '/') {
                url = url.substring(1);
            }

            RpcMethodExecutor me = RpcMethodExecutor.build().method(m).bean(bean).url(String.format("%s/%s", rootPath, url)).threadPool(threadPool).context(context);
            executor.put(me.getUrl(), me);
            log.info(String.format("[RpcServiceExecutor parseMethod] 初始化方法对应 class:%s method:%s url:%s", bean.getClass().getSimpleName(), m.getName(), me.getUrl()));
        }
    }

    private String getUrl(Object bean, ReflectionTools.AnnotationMethod am, Method m) {
        Annotation a = am.getAnnotation();

        String url = null;
        if (a instanceof PostMapping) {
            url = ((PostMapping)a).value()[0];
        } else if (a instanceof GetMapping) {
            url = ((GetMapping)a).value()[0];
        } else if (a instanceof PutMapping) {
            url = ((PutMapping)a).value()[0];
        }

        if (StringUtils.isEmpty(url)) {
            throw new RuntimeException(String.format("url不能为空，否则无法找到方法对应 class:%s method:%s", bean.getClass().getSimpleName(), m.getName()));
        }
        return url;
    }
}
